package com.pengliu.config.security;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;

/**
 * user: pengliu
 * date: 2017年9月28日
 * desc: 自定义验证码
 */
public class SecurityProvider extends DaoAuthenticationProvider {
	
	//图形验证
	public void validateCode(Authentication authentication) {
		SecurityLoginParams details = (SecurityLoginParams) authentication.getDetails();
		
		//验证码判断
		if(details.isOpenValidateCode() && !details.getValidateCode().equalsIgnoreCase(details.getSessionCode())) {
			throw new AuthenticationServiceException("验证码不正确,请重新输入!");
		}
	}

	public Authentication authenticate(Authentication authentication)throws AuthenticationException {
		
		//验证图形验证码
		validateCode(authentication);
		
		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports","Only UsernamePasswordAuthenticationToken is supported"));
		// 确定用户名
		String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();

		boolean cacheWasUsed = true;
		UserDetails user = this.getUserCache().getUserFromCache(username);

		if (user == null) {
			
			cacheWasUsed = false;

			try {
				user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);
			}
			catch (UsernameNotFoundException notFound) {
				logger.debug("用户【 " + username + "】未找到");

				if (hideUserNotFoundExceptions) {
					throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));
				}
				else {
					throw notFound;
				}
			}
			Assert.notNull(user,"retrieveUser returned null - a violation of the interface contract");
		}

		try {
			this.getPreAuthenticationChecks().check(user);
			additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);
		}
		catch (AuthenticationException exception) {
			if (cacheWasUsed) {
				// 有一个问题，所以检查后再试一次
				// 我们使用最新的数据(即不是从缓存)
				cacheWasUsed = false;
				user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);
				this.getPreAuthenticationChecks().check(user);
				additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);
			}
			else {
				throw exception;
			}
		}

		this.getPostAuthenticationChecks().check(user);

		if (!cacheWasUsed) {
			this.getUserCache().putUserInCache(user);
		}

		Object principalToReturn = user;

		if (this.isForcePrincipalAsString()) {
			principalToReturn = user.getUsername();
		}

		return createSuccessAuthentication(principalToReturn, authentication, user);
	}
}
